package asteroids.model.programs;

import java.util.HashMap;
import java.util.Map;

import asteroids.model.Ship;
import asteroids.model.programs.expressions.BasicExpression;
import asteroids.model.programs.statements.Statement;
import asteroids.model.programs.statements.ProgramStatements.SequenceStatement;
import asteroids.model.programs.types.Type;

public class Program {



	/**
	 * Initializes the master program with the given globals and sequence
	 * statement
	 */
	public Program(Map<String, Type> globals, Statement statement) {
		this.globals = globals;
		this.statement = statement;
		statement.setProgram(this);
		this.variables = new HashMap<String, BasicExpression>();
	}

	/**
	 * Copy constructor, sets the globals and sequence statement to the same as
	 * the copied master program
	 * and sets all Basic Expressions of type Self to the given ship
	 * 
	 * @param masterProgram
	 *            program to be copied
	 * @param ship
	 *            the ship all Self expressions will reference
	 */
	public Program(Program masterProgram, Ship ship) {
		this.globals = masterProgram.globals;
		this.statement = masterProgram.statement;
		this.currentStatement = (SequenceStatement) statement;
		this.self = ship;
		statement.setProgram(this);
		this.correct = true;
		this.variables = new HashMap<String, BasicExpression>();
		statement.setNextStart((SequenceStatement) statement);
	}

	/**
	 * Runs the program for the given amount of executions
	 * 
	 * @param amountOfExecutes
	 */
	public void runProgram(int amountOfExecutes) {
		if (correct) {
			try {
				currentStatement = currentStatement.execute(amountOfExecutes);
			}
			catch (Exception e) {
				System.out.println("Something went wrong");
				correct = false;
				return;
			}
		}
		else return;
	}

	public Ship getSelf() {
		return self;
	}
	
	public BasicExpression getVariableReference(String name){
		return variables.get(name);
	}
	
	public void setVariableReference(String name, BasicExpression reference){
		try{
			variables.put(name, reference);
		}
		catch (NullPointerException e){
			System.out.println("The name cannot be null");
		}	
	}
	
	public Map<String, Type> getGlobals(){
		return globals;
	}
	
	public String typeCheckProgram(){
		return statement.typeCheckStatement(null);
	}
	
	private Map<String, BasicExpression> variables;
	private Map<String, Type> globals;
	private Statement statement;
	private Ship self;
	private SequenceStatement currentStatement;
	private boolean correct;
}
